package dtaskboard.server;

import java.util.Date;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import dtaskboard.client.dto.ProjectDTO;
import dtaskboard.client.dto.RoleClass;
import dtaskboard.client.dto.SprintDTO;
import dtaskboard.client.dto.SprintStatus;
import dtaskboard.client.dto.TaskStatus;
import dtaskboard.client.exception.InvalidStateException;
import dtaskboard.client.exception.NoCurrentSprintException;
import dtaskboard.client.exception.UnauthorizedException;
import dtaskboard.client.exception.UnfinishedSprintException;
import dtaskboard.client.service.ProjectService;
import dtaskboard.entities.History;
import dtaskboard.entities.Project;
import dtaskboard.entities.Sprint;
import dtaskboard.entities.Task;
import dtaskboard.server.dao.HistoryDao;
import dtaskboard.server.dao.ProjectDao;
import dtaskboard.server.dao.SprintDao;
import dtaskboard.server.dao.TaskDao;
import dtaskboard.server.util.SecurityUtil;

public class ProjectServiceImpl extends RemoteServiceServlet implements
    ProjectService {

  private static final long serialVersionUID = 7460848383328476635L;

  @Override
  public void createProject(String projectName, String sessionId) {
    if (!SecurityUtil.hasAdmin(sessionId)) {
      throw new UnauthorizedException();
    }
    ProjectDao dao = new ProjectDao();
    Project p = new Project();
    p.setName(projectName);
    dao.save(p);
  }

  @Override
  public void updateProject(String projectName, String projectHours,
      String projectSprints, String sessionId) {
    if (!SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName)) {
      throw new UnauthorizedException();
    }

    ProjectDao pDao = new ProjectDao();
    Project p = pDao.findByName(projectName);
    p.setEstimatedSprints(Long.parseLong(projectSprints));
    p.setHours(Long.parseLong(projectHours));
    pDao.update(p);
  }

  @Override
  public void createSprint(String projectName, String plannedHours,
      Date startDate, Date endDate, String sessionId) {
    if (!SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName)) {
      throw new UnauthorizedException();
    }
    ProjectDao pDao = new ProjectDao();
    Project p = pDao.findByName(projectName);
    for (Sprint s : p.getSprints()) {
      if (SprintStatus.ONWAY.equals(s.getStatus())) {
        throw new UnfinishedSprintException();
      }
    }
    Sprint s = new Sprint();
    s.setPlannedHours(Long.parseLong(plannedHours));
    s.setStatus(SprintStatus.ONWAY);
    s.setStartDate(startDate);
    s.setEndDate(endDate);
    SprintDao sDao = new SprintDao();
    sDao.save(s);
    p.getSprints().add(s);
    pDao.update(p);
  }

  @Override
  public void closeSprint(String projectName, String achievedHours,
      String sessionId) {
    if (!SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName)) {
      throw new UnauthorizedException();
    }
    ProjectDao pDao = new ProjectDao();
    Project p = pDao.findByName(projectName);
    for (Sprint s : p.getSprints()) {
      if (SprintStatus.ONWAY.equals(s.getStatus())) {
        s.setStatus(SprintStatus.FINISHED);
        s.setAchievedHours(Long.parseLong(achievedHours));
        break;
      }
    }
  }

  @Override
  public SprintDTO getLatestSprint(String projectName, String sessionId) {
    if (!(SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName) || SecurityUtil
        .hasRole(sessionId, RoleClass.USER, projectName))) {
      throw new UnauthorizedException();
    }
    ProjectDao pDao = new ProjectDao();
    Project p = pDao.findByName(projectName);
    Sprint currentSprint = this.getCurrentSprint(p);
    if (currentSprint == null) {
      throw new NoCurrentSprintException();
    }

    return currentSprint.toDTO();
  }

  @Override
  public void createHistory(String projectName, String name, String sessionId) {
    if (!SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName)) {
      throw new UnauthorizedException();
    }
    ProjectDao pDao = new ProjectDao();
    Project p = pDao.findByName(projectName);
    Sprint current = this.getCurrentSprint(p);
    if (current == null) {
      throw new NoCurrentSprintException();
    }

    History h = new History();
    h.setName(name);
    HistoryDao hDao = new HistoryDao();
    hDao.save(h);

    current.getHistories().add(h);
    SprintDao sDao = new SprintDao();
    sDao.update(current);
  }

  private Sprint getCurrentSprint(Project p) {
    Sprint currentSprint = null;
    for (Sprint s : p.getSprints()) {
      if (SprintStatus.ONWAY.equals(s.getStatus())) {
        currentSprint = s;
        break;
      }
    }
    return currentSprint;
  }

  @Override
  public void createTask(String projectName, Long historyId, String name,
      Long estimate, String sessionId) {
    if (!SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName)) {
      throw new UnauthorizedException();
    }
    HistoryDao hDao = new HistoryDao();
    History history = hDao.find(historyId);

    Task t = new Task();
    t.setName(name);
    t.setHours(estimate);
    t.setStatus(TaskStatus.TODO);
    new TaskDao().save(t);

    history.getTasks().add(t);
    hDao.update(history);
  }

  @Override
  public void returnTask(String projectName, Long taskId, String sessionId) {
    if (!(SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName) || SecurityUtil
        .hasRole(sessionId, RoleClass.USER, projectName))) {
      throw new UnauthorizedException();
    }
    TaskDao tDao = new TaskDao();
    Task t = tDao.find(taskId);
    TaskStatus newStatus = null;
    switch (t.getStatus()) {
      case DOING:
        newStatus = TaskStatus.TODO;
        break;
      case VERIFY:
        newStatus = TaskStatus.DOING;
        break;
      case DONE:
        newStatus = TaskStatus.VERIFY;
        break;
    }
    if (newStatus == null) {
      throw new InvalidStateException();
    }
    t.setStatus(newStatus);
    if (newStatus == TaskStatus.VERIFY) {
      t.setFinishDate(null);
    }
    tDao.update(t);
  }

  @Override
  public void advanceTask(String projectName, Long taskId, String sessionId) {
    if (!(SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName) || SecurityUtil
        .hasRole(sessionId, RoleClass.USER, projectName))) {
      throw new UnauthorizedException();
    }
    TaskDao tDao = new TaskDao();
    Task t = tDao.find(taskId);
    TaskStatus newStatus = null;
    switch (t.getStatus()) {
      case TODO:
        newStatus = TaskStatus.DOING;
        break;
      case DOING:
        newStatus = TaskStatus.VERIFY;
        break;
      case VERIFY:
        newStatus = TaskStatus.DONE;
        break;
    }
    if (newStatus == null) {
      throw new InvalidStateException();
    }
    if (newStatus == TaskStatus.DONE) {
      t.setFinishDate(new Date());
    }
    t.setStatus(newStatus);
    tDao.update(t);
  }

  @Override
  public ProjectDTO getProject(String projectName, String sessionId) {
    if (!(SecurityUtil.hasRole(sessionId, RoleClass.MANAGER, projectName) || SecurityUtil
        .hasRole(sessionId, RoleClass.USER, projectName))) {
      throw new UnauthorizedException();
    }
    Project p = new ProjectDao().findByName(projectName);
    return p.toDTO();
  }
}
